package com.gitee.deeround.jdbchelper.core.impl;

import com.gitee.deeround.jdbchelper.core.DialectHelper;
import com.gitee.deeround.jdbchelper.exception.DbException;
import com.gitee.deeround.jdbchelper.in.*;
import com.gitee.deeround.jdbchelper.out.DbType;
import com.gitee.deeround.jdbchelper.util.StringUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Types;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.List;

public abstract class BaseDbAction {
    /**
     * 判断SQL语句是否是存储过程
     */
    protected boolean isProcedure(String sql) {
        sql = sql.trim();
        if (sql.startsWith("{") || sql.startsWith("call ")) {
            return true;
        }
        if (sql.indexOf(" ") == -1) {
            return true;
        }
        return false;
    }

    /**
     * SQL和参数预处理
     */
    protected SqlStatement resolve(String sql, List<SqlParameter> parameters, CommandType commandType) {
        SqlStatement statement = new SqlStatement();
        statement.setSql(sql);
        statement.setParameters(parameters);


        //sql处理
        String prepareSql = sql.trim();
        if (commandType.equals(CommandType.StoredProcedure)) {

            if (prepareSql.startsWith("{")) {
                // 不做处理
            } else if (prepareSql.toLowerCase().startsWith("call ")) {
                prepareSql = "{" + prepareSql + "}";
            } else {
                //说明只传了存储过程名称，加上call
                prepareSql = "{call " + prepareSql + "(" + placeholder((parameters != null) ? parameters.size() : 0) + ")}";
            }
            if (DbType.DM.equals(DialectHelper.getDbType())) { // 达梦目前需要去掉前后的大括号
                prepareSql = prepareSql.substring(1, prepareSql.length() - 1);
            }
        }
        statement.setPrepareSql(prepareSql);


        //参数处理
        if (parameters != null) {

            List<SqlParameter> prepareParameters = new ArrayList<>();

            //参数resolve
            for (SqlParameter parameter : parameters) {

                //格式化下Parameter
                SqlParameter temp = new SqlParameter(parameter.getParameterName(), parameter.getValue(), parameter.getParameterType(), parameter.getParameterDirection());
                resolveParameter(temp);

                //Value值类型转换
                Object value = temp.getValue();
                if (value != null) {
                    switch (temp.getParameterType()) {
                        case String: {
                            temp.setValue(value.toString());
                        }
                        break;
                        case Char: {
                            temp.setValue(value.toString());
                        }
                        break;
                        case Date: {
                            try {
                                if (Date.class.isAssignableFrom(value.getClass())) {
                                    temp.setValue(value);
                                } else {

                                    if (LocalDateTime.class.isAssignableFrom(value.getClass())) {
                                        value = ((LocalDateTime) value).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                                    } else if (LocalDate.class.isAssignableFrom(value.getClass())) {
                                        value = ((LocalDate) value).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                                    }

                                    String s = value.toString();
                                    SimpleDateFormat format;
                                    if (s.contains(" ")) {
                                        if (s.contains(".")) {
                                            format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
                                        } else {
                                            format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                        }
                                    } else {
                                        format = new SimpleDateFormat("yyyy-MM-dd");
                                    }
                                    temp.setValue(format.parse(s));
                                }
                            } catch (ParseException ex) {
                                throw new DbException("无法将" + value + "转换成Date");
                            }
                        }
                        break;
                        case Clob: {
                            temp.setValue(value.toString());
                        }
                        break;
                        case Blob: {
                            try {
                                byte[] bytes = Base64.getDecoder().decode(value.toString());
                                temp.setValue(bytes);
                            } catch (Exception e) {
                                throw new DbException("无法将" + value + "转换成Blob");
                            }
                        }
                        break;
                        case Integer: {
                            temp.setValue(new BigInteger(value.toString()));
                        }
                        break;
                        case Decimal: {
                            temp.setValue(new BigDecimal(value.toString()));
                        }
                        break;
                        case Object: {
                            temp.setValue(value);
                        }
                        break;
                        default:
                            throw new DbException("Unexpected value: " + temp.getParameterType());
                    }
                }

                prepareParameters.add(temp);
            }

            statement.setPrepareParameters(prepareParameters);

        }

        return statement;
    }

    /**
     * 参数预处理
     */
    protected void resolveParameter(SqlParameter parameter) {

        //Direction
        if (parameter.getParameterDirection() == null) {
            parameter.setParameterDirection(ParameterDirection.Input);
        }

        //ParameterType
        if (parameter.getParameterType() == null) {
            parameter.setParameterType(ParameterType.Object);
        }

        //DbType
        if (parameter.getDbType() == 0) {
            switch (parameter.getParameterType()) {
                case String: {
                    parameter.setDbType(Types.VARCHAR);
                }
                break;
                case Char: {
                    parameter.setDbType(Types.CHAR);
                }
                break;
                case Date: {
                    parameter.setDbType(Types.DATE);
                }
                break;
                case Cursor: {
                    parameter.setDbType(Types.REF_CURSOR);
                }
                break;
                case Clob: {
                    parameter.setDbType(Types.CLOB);
                }
                break;
                case Blob: {
                    parameter.setDbType(Types.BLOB);
                }
                break;
                case Integer: {
                    parameter.setDbType(Types.INTEGER);
                }
                break;
                case Decimal: {
                    parameter.setDbType(Types.DECIMAL);
                }
                break;
                case Object: {
                    parameter.setDbType(Types.JAVA_OBJECT);
                }
                break;
                default:
                    throw new DbException("Unexpected value: " + parameter.getParameterType());
            }
        }
    }

    /**
     * 生成？占位符
     */
    protected String placeholder(int size) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < size; i++) {
            sb.append((i == (size - 1)) ? "?" : "?,");
        }
        return sb.toString();
    }

    /**
     * 检测SQL
     */
    protected void checkSql(String sql) {
        //对SQL语句做安全验证
        if (StringUtils.isEmpty(sql)) {
            throw new DbException("SQL语句不能为空");
        }

    }
}
